package com.wangijun.yuan.web.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.wangijun.yuan.web.base.CommonPage;
import com.wangijun.yuan.core.base.YesNoEnum;
import com.wangijun.yuan.core.domain.*;
import com.wangijun.yuan.core.model.em.OperateTypeEnum;
import com.wangijun.yuan.web.mapper.ArticleMapper;
import com.wangijun.yuan.core.model.IdParam;
import com.wangijun.yuan.web.mapper.TagInfoMapper;
import com.wangijun.yuan.web.model.dto.*;
import com.wangijun.yuan.web.model.vo.*;
import com.wangijun.yuan.core.util.BeautifyTimeUtil;
import com.wangijun.yuan.web.util.YuanWebConst;
import com.wangijun.yuan.web.util.YuanWebUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class ArticleService extends ServiceImpl<ArticleMapper, Article> {
    private final UserService userService;
    private final OperateInfoService operateInfoService;
    private final TagInfoMapper tagInfoMapper;
    private final ArtEventService artEventService;


    private NoticeEventService getNoticeEventService() {
        return SpringUtil.getBean(NoticeEventService.class);
    }

    /**
     * 功能描述: 获取文章
     *
     * @author wlf 2024/5/25 21:39
     */
    public ArticleContentVO data(IdParam param) {
        ArticleContentVO vo = this.getBaseMapper().articleData(param.getId());
        if (vo == null) {
            throw new RuntimeException("文章不存在!");
        }
        // 总字数
        vo.setTotalWords(vo.getContent().length());
        // 阅读时长
        vo.setReadTime(BeautifyTimeUtil.beautifyTime((double) vo.getTotalWords() / 270 * 60));
        vo.setReadNum(vo.getReadNum() + 1);

        artEventService.read(vo);

        vo.setRelativeTime(YuanWebUtil.dateRelative(vo.getEditTime()));
        UserInfo userInfo = userService.get(vo.getCreateBy());
        vo.setUserInfo(new ArticleUserVO(
                userInfo.getId(),
                userInfo.getUsername(),
                userInfo.getAvatar(),
                userInfo.getSummary(),
                userInfo.getFansNum(),
                userInfo.getFavUserNum(),
                getFavFlag(userInfo.getId())));
        vo.setIsStar(isStar(vo.getId()));
        vo.setIsFav(isFavorites(vo.getId()));
        return vo;
    }

    /**
     * 功能描述: 获取当前用户是否关注用户
     *
     * @author wlf 2024/6/27 16:53
     */

    public boolean getFavFlag(Long userId) {
        if (!StpUtil.isLogin()) {
            return false;
        }
        List<Long> favUserIds = operateInfoService.getFollowUserIds();
        return favUserIds.contains(userId);
    }


    /**
     * 功能描述: 创作中心文章查询
     *
     * @author wlf 2024/6/27 9:55
     */
    public CommonPage<CreationArticleVO> creationQryArticle(CreationQryArtParam param) {
        LambdaQueryChainWrapper<Article> chainWrapper = this.lambdaQuery()
                .eq(Article::getCreateBy, StpUtil.getLoginIdAsLong())
                .eq(Article::getStatus, YesNoEnum.YES.getCode())
                .like(StrUtil.isNotBlank(param.getText()), Article::getTitle, param.getText())
                .or()
                .like(StrUtil.isNotBlank(param.getText()), Article::getSummary, param.getText());
        if (param.getOrder() == null) {
            chainWrapper.orderByDesc(Article::getEditTime);
        } else {
            switch (param.getOrder()) {
                case read_num -> chainWrapper.orderByDesc(Article::getReadNum);
                case edit_time -> chainWrapper.orderByDesc(Article::getEditTime);
                case create_time -> chainWrapper.orderByDesc(Article::getCreateTime);
            }
        }
        //　先只查一个ID
        chainWrapper.select(Article::getId);
        Page<Article> page = chainWrapper.page(param.page());
        if (page.getRecords().isEmpty()) {
            return CommonPage.toPage(page, CreationArticleVO.class);
        }

        QueryWrapper<Object> qw = new QueryWrapper<>().in("ta.id", page.getRecords().stream().map(Article::getId).toList());
        qw.orderByDesc("ta." + param.getOrder().name());
        List<CreationArticleVO> mainArticleVOPage = getBaseMapper().creationArticleList(qw);
        for (CreationArticleVO vo : mainArticleVOPage) {
            vo.setRelativeTime(YuanWebUtil.dateRelative(vo.getEditTime()));
        }
        CommonPage<CreationArticleVO> commonPage = CommonPage.toPage(page, CreationArticleVO.class);
        commonPage.setRows(mainArticleVOPage);
        return commonPage;
    }


    /**
     * 功能描述: 判断文章登录用户是否点赞
     *
     * @author wlf 2024/6/27 11:32
     */
    public boolean isStar(Long articleId) {
        if (!StpUtil.isLogin()) {
            return false;
        }
        List<Long> starArticleIds = operateInfoService.getStarArticleIds();
        return starArticleIds.contains(articleId);
    }

    /**
     * 功能描述: 是否收藏
     *
     * @author wlf 2024/6/27 14:07
     */
    public boolean isFavorites(Long articleId) {
        if (!StpUtil.isLogin()) {
            return false;
        }
        List<Long> starArticleIds = operateInfoService.getFavArticleIds();
        return starArticleIds.contains(articleId);
    }


    /**
     * 文章点赞
     */
    public boolean star(Long articleId) {
        return operateInfoService.operate(OperateTypeEnum.article_like, articleId);
    }

    /**
     * 文章收藏
     */
    public boolean favorites(Long articleId) {
        return operateInfoService.operate(OperateTypeEnum.article_fav, articleId);
    }


    /**
     * 功能描述:  多功能查询  PS 不查询博客内容主体
     *
     * @author wlf 2024/3/1 15:51
     */
    public CommonPage<MainArticleVO> articleList(MainArtQrtParam param) {

        LambdaQueryChainWrapper<Article> wrapper = lambdaQuery().eq(Article::getStatus, YesNoEnum.YES.getCode());
        boolean isEmpty = false;
        if (param.getCategoryId() != null) {
            wrapper.eq(Article::getCategoryId, param.getCategoryId());
        }
        if (param.getTopicId() != null) {
            wrapper.eq(Article::getTopicId, param.getTopicId());
        }
        if (param.getTagId() != null) {
            List<Long> idList = Db.lambdaQuery(MapArticleTag.class).eq(MapArticleTag::getTagId, param.getTagId()).list().stream().map(MapArticleTag::getArticleId).toList();
            wrapper.in(Article::getId, idList.isEmpty() ? List.of(-1) : idList);
            isEmpty = idList.isEmpty();
        }
        if (isEmpty) {
            return CommonPage.toPage(param.page(), MainArticleVO.class);
        }

        if (param.getOrder() == null) {
            wrapper.orderByDesc(Article::getEditTime);
        } else {
            switch (param.getOrder()) {
                case edit_time -> wrapper.orderByDesc(Article::getEditTime);
                case read_num -> wrapper.orderByDesc(Article::getReadNum);
            }
        }
        wrapper.select(Article::getId);
        Page<Article> page = wrapper.page(param.page());
        return getMainArticleVOCommonPage(page, param.getOrder().name());
    }


    /**
     * 功能描述: 中文分词查询
     *
     * @author wlf 2024/3/30 22:34
     */
    public CommonPage<MainArticleVO> query(SearchParam param) {
        Result result = ToAnalysis.parse(param.getText());
        List<Term> terms = result.getTerms();
        StringBuilder textStr = new StringBuilder();
        for (Term term : terms) {
            textStr.append(term.getName()).append(" ");
        }
        Page<Article> page = getBaseMapper().query(textStr.toString(), param.getOrder().name(), param.page());
        return getMainArticleVOCommonPage(page, param.getOrder().name());
    }


    /**
     * 功能描述: 根据查询查询回来的ID，补全查询文章主体内容
     *
     * @author wlf 2024/7/23 8:59
     */
    private CommonPage<MainArticleVO> getMainArticleVOCommonPage(Page<Article> page, String name) {
        if (page.getRecords().isEmpty()) {
            return CommonPage.toPage(page, MainArticleVO.class);
        }
        List<Long> idList = page.getRecords().stream().map(Article::getId).toList();
        QueryWrapper<Object> qw = new QueryWrapper<>().in("ta.id", idList);
        qw.orderByDesc("ta." + name);
        return getMainArticleVOCommonPage(page, qw);
    }

    /**
     * 功能描述: 根据文章ID查询文章数据
     *
     * @author wlf 2024/6/27 9:36
     */
    private CommonPage<MainArticleVO> getMainArticleVOCommonPage(Page<Article> page, QueryWrapper<Object> qw) {
        List<MainArticleVO> mainArticleVOPage = getBaseMapper().articleList(qw);
        List<Long> favUserIds = operateInfoService.getFollowUserIds();
        List<Long> starArticleIds = operateInfoService.getStarArticleIds();
        for (MainArticleVO vo : mainArticleVOPage) {
            UserInfo userInfo = userService.get(vo.getCreateBy());
            vo.setUserInfo(new ArticleUserVO(
                    userInfo.getId(),
                    userInfo.getUsername(),
                    userInfo.getAvatar(),
                    userInfo.getSummary(),
                    userInfo.getFansNum(),
                    userInfo.getFavUserNum(),
                    favUserIds.contains(userInfo.getId())));
            vo.setRelativeTime(YuanWebUtil.dateRelative(vo.getEditTime()));
            vo.setIsStar(starArticleIds.contains(vo.getId()));
        }
        CommonPage<MainArticleVO> commonPage = CommonPage.toPage(page, MainArticleVO.class);
        commonPage.setRows(mainArticleVOPage);
        return commonPage;
    }

    /**
     * 功能描述: 发布文章
     *
     * @author wlf 2024/2/27 15:05
     */
    @Transactional
    public Long push(ArticleParam param) {
        param.setId(IdWorker.getId());
        Article article = BeanUtil.copyProperties(param, Article.class);
        //判断话题
        checkParam(param);
        // 话题ID
        article.setTopicId(Long.valueOf(param.getTopic().value()));
        // 编辑时间
        article.setEditTime(LocalDateTime.now());
        article.setStatus(YesNoEnum.YES);
        this.save(article);

        // 用户下，
        userService.getBaseMapper().artCountAdd(article.getCreateBy(), 1);
        userService.cacheEvict(article.getCreateBy());

        getNoticeEventService().pushArt(article.getId());

        Db.save(ArticleContent.builder()
                .content(param.getContent())
                .htmlContent(param.getHtmlContent())
                .articleId(article.getId())
                .build()
        );
        // 保存标签
        for (SelectVO selectVo : param.getTagList()) {
            if (selectVo.value().equals(YuanWebConst.selectNew)) {
                // 说明是新的值
                TagInfo tagInfo = TagInfo.builder()
                        .id(IdWorker.getId())
                        .name(selectVo.label())
                        .build();
                Db.save(tagInfo);
                Db.save(
                        MapArticleTag.builder()
                                .articleId(article.getId())
                                .tagId(tagInfo.getId())
                                .build()
                );
            } else {
                // 标签下
                Long tagId = Long.valueOf(selectVo.value());
                tagInfoMapper.artNewTitle(tagId, article.getId(), article.getTitle());
                Db.save(MapArticleTag.builder().articleId(article.getId()).tagId(Long.valueOf(selectVo.value())).build());
            }
        }
        return article.getId();
    }

    /*校验参数*/
    private void checkParam(ArticleParam param) {
        SelectVO topic = param.getTopic();
        if (topic == null || topic.value().isEmpty()) {
            throw new RuntimeException("话题不可为空!");
        }
        if (param.getTagList().size() > 3) {
            throw new RuntimeException("标签数量不可超过3个");
        }
    }

    /**
     * 功能描述: 编辑文章
     *
     * @author wlf 2024/2/27 15:05
     */
    @Transactional
    public Long edit(ArticleParam param) {
        if (param.getId() == null) {
            throw new RuntimeException("文章ID不可为空");
        }
        Article article = BeanUtil.copyProperties(param, Article.class);
        //基本参数校验
        checkParam(param);
        article.setTopicId(Long.valueOf(param.getTopic().value()));
        article.setEditTime(LocalDateTime.now());
        this.updateById(article);


        getNoticeEventService().editArt(article.getId());

        Db.lambdaUpdate(ArticleContent.class)
                .eq(ArticleContent::getArticleId, article.getId())
                .remove();
        Db.save(ArticleContent.builder()
                .content(param.getContent())
                .htmlContent(param.getHtmlContent())
                .articleId(article.getId())
                .build()
        );
        Db.lambdaUpdate(MapArticleTag.class)
                .eq(MapArticleTag::getArticleId, article.getId())
                .remove();
        // 保存标签
        for (SelectVO selectVo : param.getTagList()) {
            if (selectVo.value().equals(YuanWebConst.selectNew)) {
                TagInfo tagInfo = TagInfo.builder()
                        .id(IdWorker.getId())
                        .name(selectVo.label())
                        .build();
                Db.save(tagInfo);
                Db.save(MapArticleTag.builder()
                        .articleId(article.getId())
                        .tagId(tagInfo.getId())
                        .build()
                );
            } else {
                tagInfoMapper.artNewTitle(Long.valueOf(selectVo.value()), article.getId(), article.getTitle());
                Db.save(MapArticleTag.builder().articleId(article.getId()).tagId(Long.valueOf(selectVo.value())).build());
            }
        }

        return article.getId();
    }

    /**
     * 功能描述: 保存草稿
     *
     * @author wlf 2024/2/27 15:05
     */
    @Transactional
    public Long toDraft(ArticleParam param) {
        Article article = BeanUtil.copyProperties(param, Article.class);
        //判断话题
        SelectVO topic = param.getTopic();
        if (topic == null || topic.value().isEmpty()) {
            throw new RuntimeException("话题不可为空!");
        }
        if (param.getTagList().size() > 3) {
            throw new RuntimeException("标签数量不可超过3个");
        }
        article.setTopicId(Long.valueOf(topic.value()));
        article.setEditTime(LocalDateTime.now());
        article.setStatus(YesNoEnum.NO);

        article.setId(IdWorker.getId());
        this.save(article);

        Db.lambdaUpdate(ArticleContent.class)
                .eq(ArticleContent::getArticleId, article.getId())
                .remove();
        Db.save(ArticleContent.builder()
                .content(param.getContent())
                .htmlContent(param.getHtmlContent())
                .articleId(article.getId())
                .build()
        );
        Db.lambdaUpdate(MapArticleTag.class).eq(MapArticleTag::getArticleId, article.getId()).remove();
        // 保存标签
        for (SelectVO selectVo : param.getTagList()) {
            if (selectVo.value().equals(YuanWebConst.selectNew)) {
                TagInfo tagInfo = TagInfo.builder()
                        .id(IdWorker.getId())
                        .name(selectVo.label())
                        .build();
                Db.save(tagInfo);
                Db.save(MapArticleTag.builder()
                        .articleId(article.getId())
                        .tagId(tagInfo.getId())
                        .build()
                );
            } else {
                Db.save(MapArticleTag.builder().articleId(article.getId()).tagId(Long.valueOf(selectVo.value())).build());
            }
        }

        return article.getId();
    }

    /**
     * 功能描述: 编辑文章文章数据
     *
     * @author wlf 2024/6/13 15:21
     */
    public EditArticleVO editData(Long id) {
        Article article = this.getById(id);
        EditArticleVO editArticleVo = BeanUtil.copyProperties(article, EditArticleVO.class);
        ArticleContent articleContent = Db.lambdaQuery(ArticleContent.class).eq(ArticleContent::getArticleId, article.getId()).one();
        List<TagInfo> tagInfoList = Db.lambdaQuery(TagInfo.class).in(TagInfo::getId, Db.lambdaQuery(MapArticleTag.class).eq(MapArticleTag::getArticleId, article.getId()).list().stream().map(MapArticleTag::getTagId).toList()).list();
        editArticleVo.setContent(articleContent.getContent());
        editArticleVo.setTagList(tagInfoList.stream().map(i -> new SelectVO(i.getName(), i.getId())).toList());
        TopicInfo topicInfo = Db.lambdaQuery(TopicInfo.class).eq(TopicInfo::getId, article.getTopicId()).one();
        if (topicInfo != null) {
            editArticleVo.setTopic(new SelectVO(topicInfo.getName(), topicInfo.getId()));
        } else {
            editArticleVo.setTopic(null);
        }
        return editArticleVo;
    }

    /**
     * 功能描述:  多功能查询  PS 不查询博客内容主体
     *
     * @author wlf 2024/3/1 15:51
     */
    public CommonPage<MainArticleVO> personalArticleList(PersonalArticleParam param) {
        LambdaQueryChainWrapper<Article> wrapper = lambdaQuery()
                .eq(Article::getStatus, YesNoEnum.YES.getCode());
        switch (param.getType()) {
            case create -> wrapper.in(Article::getCreateBy, param.getUserId());
            case fav -> {
                List<Long> idList = operateInfoService.getFavArticleIds(param.getUserId());
                if (idList.isEmpty()) {
                    return CommonPage.toPage(param.page(), MainArticleVO.class);
                }
                wrapper.in(Article::getId, idList);
            }
            case liked -> {
                List<Long> idList = operateInfoService.getStarArticleIds(param.getUserId());
                if (idList.isEmpty()) {
                    return CommonPage.toPage(param.page(), MainArticleVO.class);
                }
                wrapper.in(Article::getId, idList);
            }
        }
        if (StrUtil.isNotBlank(param.getText())) {
            wrapper.and(w -> w.like(Article::getTitle, param.getText())
                    .or()
                    .like(Article::getSummary, param.getText()));
        }
        wrapper.orderByDesc(Article::getEditTime);
        wrapper.select(Article::getId);
        Page<Article> page = wrapper.page(param.page());

        List<Long> idList = page.getRecords().stream().map(Article::getId).toList();
        if (idList.isEmpty()) {
            return CommonPage.toPage(page, MainArticleVO.class);
        }
        QueryWrapper<Object> qw = new QueryWrapper<>().in("ta.id", idList);
        qw.orderByDesc("ta.edit_time");

        return getMainArticleVOCommonPage(page, qw);
    }


    /**
     * 功能描述: 文章阅读榜数据
     *
     * @author wlf 2024/7/19 15:57
     */
    public CommonPage<MainArticleVO> rankArticle(RankingArtQryParam param) {
        LambdaQueryChainWrapper<Article> w = this.lambdaQuery()
                .select(Article::getId);

        switch (param.getOrder()) {
            case read_num -> w.orderByDesc(Article::getReadNum);
            case favorites -> w.orderByDesc(Article::getFavorites);
        }
        Page<Article> page = w.page(param.page());
        return getMainArticleVOCommonPage(page, param.getOrder().name());
    }

    /**
     * 功能描述: 关注文章列表
     *
     * @author wlf 2024/7/22 16:49
     */
    public CommonPage<MainArticleVO> articleFollowList(MainArtFollowQryParam param) {
        StpUtil.checkLogin();
        // 关注标签
        // 关注话题
        // 关注用户
        List<Long> favUserIds = operateInfoService.getFollowUserIds();
        List<Long> followTagIds = operateInfoService.getFollowTagIds();
        List<Long> followTopicIds = operateInfoService.getFollowTopicIds();
        if (followTopicIds.isEmpty() && favUserIds.isEmpty() && followTagIds.isEmpty()) {
            return CommonPage.toPage(param.page(), MainArticleVO.class);
        }
        LambdaQueryChainWrapper<Article> wrapper = this.lambdaQuery();
        if (!favUserIds.isEmpty()) {
            wrapper.or().in(Article::getCreateBy, favUserIds);
        }
        if (!followTagIds.isEmpty()) {
            List<MapArticleTag> list = Db.lambdaQuery(MapArticleTag.class)
                    .in(MapArticleTag::getTagId, followTagIds).select(MapArticleTag::getArticleId).list();
            if (!list.isEmpty()) {
                wrapper.or().in(Article::getCreateBy, list.stream().map(MapArticleTag::getArticleId).toList());
            }
        }
        if (!followTopicIds.isEmpty()) {
            wrapper.or().in(Article::getTopicId, followTopicIds);
        }
        switch (param.getOrder()) {
            case read_num -> wrapper.orderByDesc(Article::getReadNum);
            case edit_time -> wrapper.orderByDesc(Article::getEditTime);
        }
        Page<Article> page = wrapper.select(Article::getId)
                .page(param.page());
        return getMainArticleVOCommonPage(page, param.getOrder().name());
    }

    public List<MainArticleVO> articleRecommend(Long id) {
        // 查出文章自带的标签，话题，分类，
        Article byId = this.getById(id);

        List<Long> tagIds = Db.lambdaQuery(MapArticleTag.class).eq(MapArticleTag::getArticleId, id).list()
                .stream()
                .map(MapArticleTag::getTagId).toList();

        List<Long> artIds = Db.lambdaQuery(MapArticleTag.class).in(MapArticleTag::getTagId, tagIds).list()
                .stream().map(MapArticleTag::getArticleId).toList();

        List<Article> list = lambdaQuery()
                .eq(Article::getStatus, YesNoEnum.YES.getCode())
                .and(w -> w.in(Article::getId, artIds).or()
                        .eq(Article::getTopicId, byId.getTopicId()).or()
                        .eq(Article::getCategoryId, byId.getCategoryId())
                )
                .ne(Article::getId, id)
                .orderByDesc(Article::getReadNum).last("limit 7")
                .select(Article::getId)
                .list();
        if (list.isEmpty()) {
            return List.of();
        }
        QueryWrapper<Article> qw = new QueryWrapper<>();
        qw.in("ta.id", list.stream().map(Article::getId).toList());
        qw.orderByDesc("ta.read_num");
        List<MainArticleVO> mainArticleVOS = getBaseMapper().articleList(qw);
        for (MainArticleVO vo : mainArticleVOS) {
            vo.setRelativeTime(YuanWebUtil.dateRelative(vo.getEditTime()));
        }
        return mainArticleVOS;
    }

    /**
     * 功能描述:查询草稿
     *
     * @author wlf 2024/7/31 10:20
     */
    public CommonPage<CreationArticleVO> draftList(CreationQryDraftParam param) {
        LambdaQueryChainWrapper<Article> chainWrapper = this.lambdaQuery()
                .eq(Article::getCreateBy, StpUtil.getLoginIdAsLong())
                .eq(Article::getStatus, YesNoEnum.NO.getCode())
                .like(StrUtil.isNotBlank(param.getText()), Article::getTitle, param.getText())
                .or()
                .like(StrUtil.isNotBlank(param.getText()), Article::getSummary, param.getText());
        //　先只查一个ID
        chainWrapper.select(Article::getId);
        chainWrapper.orderByDesc(Article::getCreateTime);
        Page<Article> page = chainWrapper.page(param.page());
        if (page.getRecords().isEmpty()) {
            return CommonPage.toPage(page, CreationArticleVO.class);
        }

        QueryWrapper<Object> qw = new QueryWrapper<>().in("ta.id", page.getRecords().stream().map(Article::getId).toList());
        qw.orderByDesc("ta." + param.getOrder().name());
        List<CreationArticleVO> mainArticleVOPage = getBaseMapper().creationArticleList(qw);
        for (CreationArticleVO vo : mainArticleVOPage) {
            vo.setRelativeTime(YuanWebUtil.dateRelative(vo.getEditTime()));
        }
        CommonPage<CreationArticleVO> commonPage = CommonPage.toPage(page, CreationArticleVO.class);
        commonPage.setRows(mainArticleVOPage);
        return commonPage;
    }
}
